package cn.portx.view;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Pattern;

import javax.persistence.EntityManager;

import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.type.DoubleType;
import org.hibernate.type.StringType;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.bstek.bdf2.core.context.ContextHolder;
import com.bstek.bdf3.dorado.jpa.JpaUtil;
import com.bstek.bdf3.dorado.jpa.policy.SaveContext;
import com.bstek.bdf3.dorado.jpa.policy.impl.SmartSavePolicyAdapter;
import com.bstek.dorado.annotation.DataProvider;
import com.bstek.dorado.annotation.DataResolver;
import com.bstek.dorado.annotation.Expose;
import com.bstek.dorado.data.entity.EntityState;
import com.bstek.dorado.data.entity.EntityUtils;
import com.bstek.dorado.data.provider.Criteria;
import com.bstek.dorado.data.provider.Page;
import com.bstek.dorado.uploader.DownloadFile;
import com.bstek.dorado.uploader.annotation.FileProvider;
import com.bstek.dorado.util.proxy.ProxyBeanUtils;
import com.bstek.dorado.web.DoradoContext;

import cn.portx.ICallback;
import cn.portx.entity.Car;
import cn.portx.entity.Carrier;
import cn.portx.entity.Course;
import cn.portx.entity.Customer;
import cn.portx.entity.ExpenseItem;
import cn.portx.entity.Factory;
import cn.portx.entity.Fleet;
import cn.portx.entity.Order;
import cn.portx.entity.OrderExpense;
import cn.portx.entity.OrderSendReceive;
import cn.portx.entity.Port;
import cn.portx.entity.ShippingCompany;
import cn.portx.entity.Vessel;
import cn.portx.entity.Wharf;
import cn.portx.frame.entity.Zone;
import cn.portx.hibernate.HibernateDao;
import cn.portx.policy.IdGeneratorPolicy;
import cn.portx.policy.OrderNoGeneratorPolicy;

@Component
public class ExportPR {

	@Autowired
	private HibernateDao hibernateDao;

	@DataProvider
	@Transactional(readOnly = true)
	public Order loadOrder(String orderId) {
		if (StringUtils.isEmpty(orderId)) {
			return null;
		}
		List<Order> list = this.loadOrders(orderId);
		return list.isEmpty() ? null : list.get(0);
	}

	public List<Order> loadOrders(String... ids) {
		List<Order> list = JpaUtil.linq(Order.class).collect(Customer.class, "customerId").collect(Fleet.class, "fleetId",
				"destFleetId")/* .collect(Car.class, "carId", "destCarId") */
				.collect(ShippingCompany.class, "shippingCompanyId").collect(Vessel.class, "vesselId").collect(Wharf.class, "wharfId")
				.collect(Port.class, "startPortId", "endPortId").collect(Carrier.class, "xsId").in("id", ids).list();
		return list;
	}

	@DataProvider
	@Transactional(readOnly = true)
	public void loadOrders(final Page<Order> page, Criteria criteria) {
		JpaUtil.linq(Order.class).collect(Customer.class, "customerId").collect(Fleet.class, "fleetId",
				"destFleetId")/* .collect(Car.class, "carId", "destCarId") */
				.collect(ShippingCompany.class, "shippingCompanyId").collect(Vessel.class, "vesselId").collect(Wharf.class, "wharfId")
				.collect(Port.class, "startPortId", "endPortId").collect(Carrier.class, "xsId").collect(Order.class, "appendedId").collectSelect(Order.class, "id", "orderNo")
				.equal("type", "0").isNull("targetId").where(criteria).desc("orderNo").paging(page);
	}

	@DataProvider
	@Transactional(readOnly = true)
	public List<ExpenseItem> loadExpenseItem(String type) {
		return JpaUtil.linq(ExpenseItem.class).equal("type", type).list();
	}

	@DataProvider
	@Transactional(readOnly = true)
	public List<OrderSendReceive> loadOrderSendReceives(Map<String, Object> params) {
		String orderId = (String) params.get("orderId");
		String type = params.get("type").toString();
		return JpaUtil.linq(OrderSendReceive.class).equal("orderId", orderId).equal("type", type).list();
	}

	@DataProvider
	@Transactional
	public synchronized List<OrderExpense> loadExpense(String orderId, int type) {
		List<OrderExpense> oeList = JpaUtil.linq(OrderExpense.class).collect(ExpenseItem.class, "expenseItemId").equal("orderId", orderId).equal("type", type + "").list();
		List<String> ids = new ArrayList<String>();
		for (OrderExpense oe : oeList) {
			ids.add(oe.getExpenseItemId());
		}
		int financeEnd = JpaUtil.linq(Order.class, Integer.class).select("financeEnd").idEqual(orderId).findOne();
		if (financeEnd == 0) {
			// 财务未完结---------------------初始化订单费用表信息（对常用的费用项）
			List<OrderExpense> newOeList = new ArrayList<OrderExpense>();
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("type", type + "");
			String sql = "select {ei.*} from t_expense_item ei where ei.in_common_use_=1 and ei.type_=:type";
			if (ids.size() > 0) {
				sql += " and ei.id_ not in :ids";
				params.put("ids", ids);
			}
			Session session = this.hibernateDao.getSession(OrderExpense.class);
			SQLQuery query = session.createSQLQuery(sql);
			query.setProperties(params);
			query.addEntity("ei", ExpenseItem.class);
			List<ExpenseItem> items = query.list();
			for (ExpenseItem ei : items) {
				OrderExpense oe = new OrderExpense();
				oe.setOrderId(orderId);
				oe.setExpenseItem(ei);
				oe.setExpenseItemId(ei.getId());
				oe.setType(ei.getType());
				oe.setExpenseVal(0d);
				oe.setJszt("0");
				oe.setKpzt("0");
				if (type == 0) {
					// 应收
					oe.setDw(StringUtils.isEmpty(ei.getDw()) ? "5" : ei.getDw());// 默认客户
				} else if (type == 1) {
					// 应付
					oe.setDw(ei.getDw());
				}
				newOeList.add(oe);
			}
			JpaUtil.persist(newOeList);
			oeList.addAll(newOeList);
			// -------------------------------------------------------------------------------
		}

		return oeList;
	}

	@DataProvider
	@Transactional(readOnly = true)
	public void loadCustomers(Page<Customer> page, Map<String, Object> params) {
		if (params == null) {
			params = new HashMap<String, Object>();
		}
		String filterValue = (String) params.get("filterValue");
		JpaUtil.linq(Customer.class).addIf(filterValue).or().like("code", filterValue + "%").like("name", filterValue + "%").end().endIf().paging(page);
	}

	@DataProvider
	@Transactional(readOnly = true)
	public List<Factory> loadFactories(Map<String, Object> params) {
		if (params == null) {
			params = new HashMap<String, Object>();
		}
		String customerId = (String) params.get("customerId");
		String filterValue = (String) params.get("filterValue");
		return JpaUtil.linq(Factory.class).equal("customerId", customerId).addIf(filterValue).or().like("code", filterValue + "%").like("name", filterValue + "%").end().endIf()
				.list();
	}

	@DataProvider
	@Transactional(readOnly = true)
	public void loadFleets(Page<Fleet> page, Map<String, Object> params) {
		if (params == null) {
			params = new HashMap<String, Object>();
		}
		String filterValue = (String) params.get("filterValue");
		String type = (String) params.get("type");
		JpaUtil.linq(Fleet.class).addIf(filterValue).or().like("code", filterValue + "%").like("name", filterValue + "%").end().endIf().in("category", type, "2").paging(page);
	}

	@DataProvider
	@Transactional(readOnly = true)
	public void loadCars(Page<Fleet> page, Map<String, Object> params) {
		if (params == null) {
			params = new HashMap<String, Object>();
		}
		String filterValue = (String) params.get("filterValue");
		String fleetId = (String) params.get("fleetId");
		JpaUtil.linq(Car.class).addIf(fleetId).equal("fleetId", fleetId).endIf().addIf(filterValue).or().like("no", filterValue + "%").like("name", filterValue + "%").end().endIf()
				.paging(page);
	}

	@DataProvider
	@Transactional(readOnly = true)
	public void loadShippingCompanies(Page<ShippingCompany> page, Map<String, Object> params) {
		if (params == null) {
			params = new HashMap<String, Object>();
		}
		String filterValue = (String) params.get("filterValue");
		JpaUtil.linq(ShippingCompany.class).addIf(filterValue).or().like("code", filterValue + "%").like("name", filterValue + "%").end().endIf().paging(page);
	}

	@DataProvider
	@Transactional(readOnly = true)
	public void loadCarriers(Page<Carrier> page, Map<String, Object> params) {
		if (params == null) {
			params = new HashMap<String, Object>();
		}
		String filterValue = (String) params.get("filterValue");
		JpaUtil.linq(Carrier.class).addIf(filterValue).or().like("code", filterValue + "%").like("name", filterValue + "%").end().endIf().paging(page);
	}

	@DataProvider
	@Transactional(readOnly = true)
	public void loadVesselsForJK(Page<Course> page, Map<String, Object> params) {
		if (params == null) {
			params = new HashMap<String, Object>();
		}
		String shippingCompanyId = (String) params.get("shippingCompanyId");
		String filterValue = (String) params.get("filterValue");
		JpaUtil.linq(Vessel.class).equal("shippingCompanyId", shippingCompanyId).addIf(filterValue).or().like("code", filterValue + "%").like("name", filterValue + "%").end()
				.endIf().paging(page);
	}

	@DataProvider
	@Transactional(readOnly = true)
	public void loadVessels(Page<Vessel> page, Map<String, Object> params) {
		if (params == null) {
			params = new HashMap<String, Object>();
		}
		String shippingCompanyId = (String) params.get("shippingCompanyId");
		String filterValue = (String) params.get("filterValue");
		Map<String, Object> parametersMap = new HashMap<String, Object>();
		parametersMap.put("shippingCompanyId", shippingCompanyId);
		String sql = "select {c.*},{v.*},{sp.*},{ep.*} from t_vessel v left join t_course c on c.vessel_id_=v.id_ left join t_port sp on c.start_port_id_=sp.id_ left join t_port ep on c.end_port_id_=ep.id_ where v.shipping_company_id_=:shippingCompanyId";
		String countSql = "select count(c.id_) from t_vessel v left join t_course c on c.vessel_id_=v.id_ left join t_port sp on c.start_port_id_=sp.id_ left join t_port ep on c.end_port_id_=ep.id_ where v.shipping_company_id_=:shippingCompanyId";
		if (StringUtils.isNotBlank(filterValue)) {
			sql += " and (v.code_ like :filterValue or v.name_ like :filterValue)";
			countSql += " and (v.code_ like :filterValue or v.name_ like :filterValue)";
			parametersMap.put("filterValue", filterValue + "%");
		}
		this.hibernateDao.pagingSQLQuery(page, sql, countSql, parametersMap, new ICallback<Void, SQLQuery>() {

			@Override
			public Void execute(SQLQuery query) {
				query.addEntity("c", Course.class).addEntity("v", Vessel.class).addEntity("sp", Port.class).addEntity("ep", Port.class);
				return null;
			}
		}, new ICallback<List<?>, List<?>>() {

			@Override
			public List<?> execute(List<?> list) {
				List<Vessel> result = new ArrayList<Vessel>();
				for (Object object : list) {
					Object[] array = (Object[]) object;
					try {
						Vessel v = EntityUtils.toEntity(array[1]);
						EntityUtils.setValue(v, "course", array[0]);
						EntityUtils.setValue(v, "startPort", array[2]);
						EntityUtils.setValue(v, "endPort", array[3]);
						result.add(v);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				return result;
			}
		}, this.hibernateDao.getSession(Course.class));
	}

	@DataProvider
	@Transactional(readOnly = true)
	public void loadWharfs(Page<Wharf> page, Map<String, Object> params) {
		if (params == null) {
			params = new HashMap<String, Object>();
		}
		String portId = (String) params.get("portId");
		String filterValue = (String) params.get("filterValue");
		JpaUtil.linq(Wharf.class).equal("portId", portId).addIf(filterValue).or().like("code", filterValue + "%").like("name", filterValue + "%").end().endIf().paging(page);
	}

	@DataProvider
	@Transactional
	public List<Zone> loadZone(String parentId) throws Exception {
		ZonePR zonePR = DoradoContext.getCurrent().getApplicationContext().getBean(ZonePR.class);
		return zonePR.loadZone(parentId);
	}

	/**
	 * 保存订单
	 * 
	 * @param orders
	 */
	@DataResolver
	@Transactional
	public void saveOrder(Order order) {
		List<Order> orders = new ArrayList<Order>();
		orders.add(order);
		this.saveOrders(orders);
	}

	/**
	 * 保存订单
	 * 
	 * @param orders
	 */
	@DataResolver
	@Transactional
	public void saveOrders(List<Order> orders) {
		JpaUtil.save(orders, new OrderSmartSavePolicyAdapter());
	}

	@Expose
	public String checkMultipleCntno(String cntnos) {
		String[] array = StringUtils.split(cntnos, ",");
		for (String cntNo : array) {
			String result = this.checkCnt(cntNo);
			if (result != null) {
				return result;
			}
		}
		return null;
	}

	@Expose
	public String checkCnt(String cntNo) {
		if(StringUtils.isBlank(cntNo)){
			return null;
		}
//		if (cntNo.length() != 11)
//			return "箱号[" + cntNo + "]规则错误！必须是11位长度";
		
		if(!Pattern.matches("^[A-Z]{4}\\d{7}$",cntNo)){
			return "箱号[" + cntNo + "]规则错误！必须以4个大写字母开头，然后紧跟7位数字！";
		}
		
		char[] cntChar = cntNo.toCharArray();
		int totalValue = 0;
		for (int i = 1; i < cntChar.length; i++) {
			totalValue += getCharValue(cntChar[i - 1]) * Math.pow(2, i - 1);
		}
		int sign = totalValue % 11;
		int last = cntChar[10] - '0';
		if (last != sign) {
//			return "箱号[" + cntNo + "]规则错误！校验码错误！"; // 2017-11-24，根据客户要求注释掉了，直接返回null
			return null;
		} else {
			return null;
		}
	}

//	public static void main(String[] args) {
//		ExportPR p = new ExportPR();
//		System.out.println(p.checkCnt("XINU1590480"));;
//	}
	
	private int getCharValue(char value) {
		int result = 0;

		switch (value) {
		case '0':
			result = 0;
			break;
		case '1':
			result = 1;
			break;
		case '2':
			result = 2;
			break;
		case '3':
			result = 3;
			break;
		case '4':
			result = 4;
			break;
		case '5':
			result = 5;
			break;
		case '6':
			result = 6;
			break;
		case '7':
			result = 7;
			break;
		case '8':
			result = 8;
			break;
		case '9':
			result = 9;
			break;
		case 'A':
			result = 10;
			break;
		case 'B':
			result = 12;
			break;
		case 'C':
			result = 13;
			break;
		case 'D':
			result = 14;
			break;
		case 'E':
			result = 15;
			break;
		case 'F':
			result = 16;
			break;
		case 'G':
			result = 17;
			break;
		case 'H':
			result = 18;
			break;
		case 'I':
			result = 19;
			break;
		case 'J':
			result = 20;
			break;
		case 'K':
			result = 21;
			break;
		case 'L':
			result = 23;
			break;
		case 'M':
			result = 24;
			break;
		case 'N':
			result = 25;
			break;
		case 'O':
			result = 26;
			break;
		case 'P':
			result = 27;
			break;
		case 'Q':
			result = 28;
			break;
		case 'R':
			result = 29;
			break;
		case 'S':
			result = 30;
			break;
		case 'T':
			result = 31;
			break;
		case 'U':
			result = 32;
			break;
		case 'V':
			result = 34;
			break;
		case 'W':
			result = 35;
			break;
		case 'X':
			result = 36;
			break;
		case 'Y':
			result = 37;
			break;
		case 'Z':
			result = 38;
			break;
		}
		return result;
	}

	/**
	 * 根据原订单生成单箱订单（即数量是1）
	 * 
	 * @param order
	 */
	private static void generateOrder(Order order, String baseOrderNo, int index) {
		for (int i = 1; i < index; i++) {
			Order target = new Order();
			Order source = order;
			String[] ignoreProperties = new String[] { "id", "orderNo", "customer", "orderSend", "orderReceive", "receiveExpense", "payExpense", "costExpense", "car", "destCar",
					"fleet", "destFleet", "shippingCompany", "xs", "vessel", "startPort", "endPort", "wharf", "orderDate", "orderNo", /* "billNo", */ "cntNo", "sealNo", "billNo2",
					"cntNo2", "sealNo2", "createUser", "createDate" };
			BeanUtils.copyProperties(source, target, ignoreProperties);
			target.setId(IdGeneratorPolicy.getId());
			target.setQuantity(1);
			target.setOrderNo(baseOrderNo + "-" + StringUtils.leftPad(String.valueOf(i + 1), 3, "0"));
			if (StringUtils.contains(order.getCntNo(), ",")) {
				target.setCntNo(StringUtils.split(order.getCntNo(), ",")[i]);
			}

			List<OrderExpense> receiveExpense = new ArrayList<OrderExpense>();
			List<OrderExpense> payExpense = new ArrayList<OrderExpense>();
			List<OrderExpense> costExpense = new ArrayList<OrderExpense>();

			List<OrderExpense> list = order.getReceiveExpense();
			for (OrderExpense oe : list) {
				try {
					OrderExpense oeTarget = new OrderExpense();
					BeanUtils.copyProperties(ProxyBeanUtils.getProxyTarget(oe), oeTarget, new String[] { "order", "expenseItem" });
					oeTarget.setId(IdGeneratorPolicy.getId());
					oeTarget.setOrderId(target.getId());
					receiveExpense.add(oeTarget);
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
			list = order.getPayExpense();
			for (OrderExpense oe : list) {
				try {
					OrderExpense oeTarget = new OrderExpense();
					BeanUtils.copyProperties(ProxyBeanUtils.getProxyTarget(oe), oeTarget, new String[] { "order", "expenseItem", "createUser", "createDate" });
					oeTarget.setId(IdGeneratorPolicy.getId());
					oeTarget.setOrderId(target.getId());
					payExpense.add(oeTarget);
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
			list = order.getCostExpense();
			for (OrderExpense oe : list) {
				try {
					OrderExpense oeTarget = new OrderExpense();
					BeanUtils.copyProperties(ProxyBeanUtils.getProxyTarget(oe), oeTarget, new String[] { "order", "expenseItem", "createUser", "createDate" });
					oeTarget.setId(IdGeneratorPolicy.getId());
					oeTarget.setOrderId(target.getId());
					costExpense.add(oeTarget);
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
			target.setReceiveExpense(receiveExpense);
			target.setPayExpense(payExpense);
			target.setCostExpense(costExpense);

			List<OrderSendReceive> orderSend = new ArrayList<OrderSendReceive>();
			List<OrderSendReceive> orderReceive = new ArrayList<OrderSendReceive>();

			List<OrderSendReceive> list2 = order.getOrderSend();
			for (OrderSendReceive oe : list2) {
				try {
					OrderSendReceive osrTarget = new OrderSendReceive();
					BeanUtils.copyProperties(ProxyBeanUtils.getProxyTarget(oe), osrTarget, new String[] { "order" });
					osrTarget.setId(IdGeneratorPolicy.getId());
					osrTarget.setOrderId(target.getId());
					orderSend.add(osrTarget);
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
			list2 = order.getOrderReceive();
			for (OrderSendReceive oe : list2) {
				try {
					OrderSendReceive osrTarget = new OrderSendReceive();
					BeanUtils.copyProperties(ProxyBeanUtils.getProxyTarget(oe), osrTarget, new String[] { "order" });
					osrTarget.setId(IdGeneratorPolicy.getId());
					osrTarget.setOrderId(target.getId());
					orderReceive.add(osrTarget);
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
			target.setOrderSend(orderSend);
			target.setOrderReceive(orderReceive);

			// Order togetherOrder = generateTogetherOrder(target);
			// if (togetherOrder != null) {
			// target.setTogetherId(togetherOrder.getId());
			//
			// togetherOrder.setBillNo(target.getBillNo());
			// togetherOrder.setCntNo(null);
			// togetherOrder.setSealNo(null);
			// togetherOrder.setBillNo2(null);
			// togetherOrder.setCntNo2(null);
			// togetherOrder.setSealNo2(null);
			//
			// JpaUtil.merge(togetherOrder);
			// }

			JpaUtil.persist(target);
		}
	}

	/**
	 * 生成拼箱订单
	 * 
	 * @param order
	 * @return
	 */
//	private static Order generateTogetherOrder(Order order) {
//		if (order.getSfst() != 1) {
//			return null;
//		}
//		Order target = new Order();
//		Order source = null;
//		try {
//			source = (Order) ProxyBeanUtils.getProxyTarget(order);
//		} catch (Exception e) {
//			throw new RuntimeException(e);
//		}
//		String[] ignoreProperties = new String[] { "customer", "orderSend", "orderReceive", "receiveExpense", "payExpense", "costExpense", "car", "destCar", "fleet", "destFleet",
//				"shippingCompany", "xs", "vessel", "startPort", "endPort", "wharf", "orderDate", "orderNo", "billNo", "cntNo", "sealNo", "billNo2", "cntNo2", "sealNo2" };
//		BeanUtils.copyProperties(source, target, ignoreProperties);
//		target.setId(null);
//		target.setTogetherId(order.getId());
//		target.setBillNo(order.getBillNo2());
//		target.setCntNo(order.getCntNo2());
//		target.setSealNo(order.getSealNo2());
//		target.setBillNo2(order.getBillNo());
//		target.setCntNo2(order.getCntNo());
//		target.setSealNo2(order.getSealNo());
//
//		JpaUtil.persist(target);
//
//		List<OrderExpense> list = order.getReceiveExpense();
//		for (OrderExpense oe : list) {
//			try {
//				OrderExpense oeTarget = new OrderExpense();
//				BeanUtils.copyProperties(ProxyBeanUtils.getProxyTarget(oe), oeTarget, new String[] { "order", "expenseItem" });
//				oeTarget.setId(null);
//				oeTarget.setOrderId(target.getId());
//				JpaUtil.persist(oeTarget);
//			} catch (Exception e) {
//				e.printStackTrace();
//				throw new RuntimeException(e);
//			}
//		}
//		list = order.getPayExpense();
//		for (OrderExpense oe : list) {
//			try {
//				OrderExpense oeTarget = new OrderExpense();
//				BeanUtils.copyProperties(ProxyBeanUtils.getProxyTarget(oe), oeTarget, new String[] { "order", "expenseItem" });
//				oeTarget.setId(null);
//				oeTarget.setOrderId(target.getId());
//				JpaUtil.persist(oeTarget);
//			} catch (Exception e) {
//				throw new RuntimeException(e);
//			}
//		}
//		list = order.getCostExpense();
//		for (OrderExpense oe : list) {
//			try {
//				OrderExpense oeTarget = new OrderExpense();
//				BeanUtils.copyProperties(ProxyBeanUtils.getProxyTarget(oe), oeTarget, new String[] { "order", "expenseItem" });
//				oeTarget.setId(null);
//				oeTarget.setOrderId(target.getId());
//				JpaUtil.persist(oeTarget);
//			} catch (Exception e) {
//				throw new RuntimeException(e);
//			}
//		}
//
//		List<OrderSendReceive> list2 = order.getOrderSend();
//		for (OrderSendReceive oe : list2) {
//			try {
//				OrderSendReceive osrTarget = new OrderSendReceive();
//				BeanUtils.copyProperties(ProxyBeanUtils.getProxyTarget(oe), osrTarget, new String[] { "order" });
//				osrTarget.setId(null);
//				osrTarget.setOrderId(target.getId());
//				JpaUtil.persist(osrTarget);
//			} catch (Exception e) {
//				throw new RuntimeException(e);
//			}
//		}
//		list2 = order.getOrderReceive();
//		for (OrderSendReceive oe : list2) {
//			try {
//				OrderSendReceive osrTarget = new OrderSendReceive();
//				BeanUtils.copyProperties(ProxyBeanUtils.getProxyTarget(oe), osrTarget, new String[] { "order" });
//				osrTarget.setId(null);
//				osrTarget.setOrderId(target.getId());
//				JpaUtil.persist(osrTarget);
//			} catch (Exception e) {
//				throw new RuntimeException(e);
//			}
//		}
//		return target;
//	}

	@Expose
	@Transactional(readOnly = true)
	public List<Map<String, Object>> getAppend(String id) {
		String hql = "select new map(id as id,orderNo as orderNo) from " + Order.class.getName() + " where appendedId=:orderId";
		return this.hibernateDao.getSession(Order.class).createQuery(hql).setString("orderId", id).list();
	}

	/**
	 * 设置双拖或拆分双拖
	 * 
	 * @param orderId_1
	 * @param orderId_2
	 * @param type
	 *            0：设置；1：拆分
	 */
	@Expose
	@Transactional
	public Object setSt(Map<String, Object> params) throws Exception {
		int type = (int) params.get("type"); 

		if (type == 0) {
			String orderId_1 = (String) params.get("orderId_1");
			String orderId_2 = (String) params.get("orderId_2");
			Order order1 = JpaUtil.linq(Order.class).idEqual(orderId_1).findOne();
			Order order2 = JpaUtil.linq(Order.class).idEqual(orderId_2).findOne();
			if (order1.getSfst() == 1) {
				throw new IllegalStateException("订单（" + order1.getOrderNo() + "）已经是双拖单，不能进行该操作！");
			}
			if (order2.getSfst() == 1) {
				throw new IllegalStateException("订单（" + order2.getOrderNo() + "）已经是双拖单，不能进行该操作！");
			}
			if (!Arrays.asList("-1", "0", "1", "2", "3", "4", "5", "6", "8", "10").contains(order1.getBoxType())) {
				throw new IllegalStateException("订单（" + order1.getOrderNo() + "）不是20尺箱，不能进行该操作！");
			}
//			if (!StringUtils.equals(order1.getBoxType(), "0") && !StringUtils.equals(order1.getBoxType(), "1")) {
//				throw new IllegalStateException("订单（" + order1.getOrderNo() + "）不是20尺箱，不能进行该操作！");
//			}
			if (!Arrays.asList("-1", "0", "1", "2", "3", "4", "5", "6", "8", "10").contains(order2.getBoxType())) {
				throw new IllegalStateException("订单（" + order2.getOrderNo() + "）不是20尺箱，不能进行该操作！");
			}
//			if (!StringUtils.equals(order2.getBoxType(), "0") && !StringUtils.equals(order2.getBoxType(), "1")) {
//				throw new IllegalStateException("订单（" + order2.getOrderNo() + "）不是20尺箱，不能进行该操作！");
//			}
			if (StringUtils.isNotBlank(order1.getAppendedId())) {
				throw new IllegalStateException("订单（" + order1.getOrderNo() + "）是费用追加单子，不能进行该操作！");
			}
			if (StringUtils.isNotBlank(order2.getAppendedId())) {
				throw new IllegalStateException("订单（" + order2.getOrderNo() + "）是费用追加单子，不能进行该操作！");
			}
			validateOrderExpenseJsztByOrder(order1);
			validateOrderExpenseJsztByOrder(order2);

			if (order1.getFinanceEnd() == 1) {
				throw new IllegalStateException("订单（" + order1.getOrderNo() + "）财务已完结，不能进行该操作！");
			}
			if (order2.getFinanceEnd() == 1) {
				throw new IllegalStateException("订单（" + order2.getOrderNo() + "）财务已完结，不能进行该操作！");
			}
			if (!StringUtils.equals(order1.getCustomerId(), order2.getCustomerId())) {
				throw new IllegalStateException("两个订单客户不一致，不能进行该操作！");
			}
			if (!StringUtils.equals(order1.getCarId(), order2.getCarId())) {
				throw new IllegalStateException("两个订单车牌号不一致，不能进行该操作！");
			}

			Order order = new Order();
			String[] ignoreProperties = new String[] { "id", "orderNo", "createUser", "createDate" };
			if (order1.getOrderNo().compareTo(order2.getOrderNo()) > 0) {
				BeanUtils.copyProperties(order2, order, ignoreProperties);
				order.setBillNo2(order1.getBillNo());
				order.setCntNo2(order1.getCntNo());
				order.setSealNo2(order1.getSealNo());
			} else {
				BeanUtils.copyProperties(order1, order, ignoreProperties);
				order.setBillNo2(order2.getBillNo());
				order.setCntNo2(order2.getCntNo());
				order.setSealNo2(order2.getSealNo());
			}
			for (Field field : this.getNotEqualFields(order1, order2, "billNo", "cntNo", "sealNo", "billNo2", "cntNo2", "sealNo2")) {
				FieldUtils.writeField(field, order, null, true);
			}
			order.setQuantity(2);
			order.setSfst(1);
			JpaUtil.persist(order);

			List<OrderSendReceive> osrList1 = JpaUtil.linq(OrderSendReceive.class).equal("orderId", order1.getId()).list();
			List<OrderSendReceive> osrList2 = JpaUtil.linq(OrderSendReceive.class).equal("orderId", order2.getId()).list();
			for (OrderSendReceive osr1 : osrList1) {
				OrderSendReceive osr = new OrderSendReceive();
				BeanUtils.copyProperties(osr1, osr, "id", "orderId", "createUser", "createDate");
				osr.setOrderId(order.getId());
				for (Iterator<OrderSendReceive> iter = osrList2.iterator(); iter.hasNext();) {
					OrderSendReceive osr2 = iter.next();
					if (StringUtils.equals(osr1.getFactoryId(), osr2.getFactoryId())) {
						if (StringUtils.equals(osr1.getType(), osr2.getType())) {
							iter.remove();
						}
					}
				}
				JpaUtil.persist(osr);
			}
			for (OrderSendReceive osr2 : osrList2) {
				OrderSendReceive osr = new OrderSendReceive();
				BeanUtils.copyProperties(osr2, osr, "id", "orderId", "createUser", "createDate");
				osr.setOrderId(order.getId());
				JpaUtil.persist(osr);
			}

			List<OrderExpense> list1 = JpaUtil.linq(OrderExpense.class).equal("orderId", order1.getId()).list();
			List<OrderExpense> list2 = JpaUtil.linq(OrderExpense.class).equal("orderId", order2.getId()).list();
			for (OrderExpense oe1 : list1) {
				OrderExpense oe = new OrderExpense();
				BeanUtils.copyProperties(oe1, oe, "id", "orderId", "createUser", "createDate");
				oe.setOrderId(order.getId());
				for (Iterator<OrderExpense> iter = list2.iterator(); iter.hasNext();) {
					OrderExpense oe2 = iter.next();
					if (StringUtils.equals(oe1.getExpenseItemId(), oe2.getExpenseItemId())) {
						oe.setExpenseVal(oe1.getExpenseVal() + oe2.getExpenseVal());
						iter.remove();
						break;
					}
				}
				JpaUtil.persist(oe);
			}
			for (OrderExpense oe2 : list2) {
				OrderExpense oe = new OrderExpense();
				BeanUtils.copyProperties(oe2, oe, "id", "orderId", "createUser", "createDate");
				oe.setOrderId(order.getId());
				JpaUtil.persist(oe);
			}

			order1.setTargetId(order.getId());
			order2.setTargetId(order.getId());
			JpaUtil.merge(order1);
			JpaUtil.merge(order2);
			return this.loadOrder(order.getId());
		} else {
			//拆双拖
			List<Order> list = new ArrayList<Order>();
			List<String> ids = (List<String>) params.get("ids");
			List<Order> orders = JpaUtil.linq(Order.class).in("id", ids.toArray(new String[ids.size()])).list();
			for (Order order : orders) {
				if (order.getSfst() != 1) {
					throw new IllegalStateException("订单（" + order.getOrderNo() + "）不具有双拖关联单子，不能进行该操作！");
				}
				if (order.getFinanceEnd() == 1) {
					throw new IllegalStateException("订单（" + order.getOrderNo() + "）财务已完结，不能进行该操作！");
				}
				if (StringUtils.isNotBlank(order.getAppendedId())) {
					throw new IllegalStateException("订单（" + order.getOrderNo() + "）是费用追加单子，不能进行该操作！");
				}
				this.validateOrderExpenseJsztByOrder(order);

				List<String> sourceOrderIds = JpaUtil.linq(Order.class, String.class).selectId().equal("targetId", order.getId()).list();
				if (sourceOrderIds.isEmpty()) {
					//该订单不是合并而成的
					Order newOrder = new Order();
					String[] ignoreProperties = new String[] { "id", "orderNo", "quantity", "sfst", "createUser", "createDate", "billNo", "cntNo", "sealNo", "billNo2", "cntNo2",
							"sealNo2" };
					BeanUtils.copyProperties(order, newOrder, ignoreProperties);
					newOrder.setQuantity(1);
					newOrder.setSfst(0);
					newOrder.setBillNo(order.getBillNo2());
					newOrder.setCntNo(order.getCntNo2());
					newOrder.setSealNo(order.getSealNo2());
					JpaUtil.persist(newOrder);

					List<OrderSendReceive> osrList = JpaUtil.linq(OrderSendReceive.class).equal("orderId", order.getId()).list();
					for (OrderSendReceive osr : osrList) {
						OrderSendReceive newOsr = new OrderSendReceive();
						BeanUtils.copyProperties(osr, newOsr, "id", "orderId", "createUser", "createDate");
						newOsr.setOrderId(newOrder.getId());
						JpaUtil.persist(newOsr);
					}
					List<OrderExpense> oeList = JpaUtil.linq(OrderExpense.class).equal("orderId", order.getId()).list();
					for (OrderExpense oe : oeList) {
						OrderExpense newOe = new OrderExpense();
						BeanUtils.copyProperties(oe, newOe, "id", "orderId", "createUser", "createDate");
						newOe.setOrderId(newOrder.getId());
						newOe.setExpenseVal(oe.getExpenseVal() / 2);
						oe.setExpenseVal(oe.getExpenseVal() / 2);
						JpaUtil.persist(newOe);
						JpaUtil.merge(oe);
					}

					order.setQuantity(1);
					order.setSfst(0);
					order.setBillNo2(null);
					order.setCntNo2(null);
					order.setSealNo2(null);
					JpaUtil.merge(order);
					list.addAll(this.loadOrders(order.getId(), newOrder.getId()));
				} else {
					//该订单是合并而成的
					JpaUtil.linu(Order.class).set("targetId", null).in("id", sourceOrderIds.toArray()).update();
					JpaUtil.remove(order);
					list.addAll(this.loadOrders(sourceOrderIds.toArray(new String[] {})));
				}
			}
			return list;
		}

	}

	private List<Field> getNotEqualFields(Order order1, Order order2, String... ignoreProperties) throws IllegalArgumentException, IllegalAccessException {
		List<Field> list = new ArrayList<Field>();
		List<String> ignoreFields = Arrays.asList(ignoreProperties);
		Field[] fields = FieldUtils.getAllFields(Order.class);
		for (Field field : fields) {
			if (ignoreFields.contains(field.getName())) {
				continue;
			}
			if (!field.isAccessible()) {
				field.setAccessible(true);
			}
			if (Date.class.isAssignableFrom(field.getType())) {
				//同一天，则认为相同，以较早订单的时间为准
				if (field.get(order1) == null || field.get(order2) == null) {
					list.add(field);
				} else if (!DateUtils.truncatedEquals((Date) field.get(order1), (Date) field.get(order2), Calendar.DAY_OF_MONTH)) {
					//不是同一天
					list.add(field);
				}
			} else {
				if (ObjectUtils.notEqual(field.get(order1), field.get(order2))) {
					list.add(field);
				}
			}
		}
		return list;
	}

	/**
	 * 判断订单中费用是否正处核销中
	 * 
	 * @param order
	 */
	private void validateOrderExpenseJsztByOrder(Order order) {
		Session session = this.hibernateDao.getSession(OrderExpense.class);
		String hql = "select count(*) from " + OrderExpense.class.getName() + " where orderId=:orderId and jszt<>'0'";
		Number number = (Number) session.createQuery(hql).setString("orderId", order.getId()).uniqueResult();
		if (number.intValue() > 0) {
			throw new IllegalStateException("订单（" + order.getOrderNo() + "）的费用项正处于核销中，因此不能进行该操作！");
		}
	}

	/**
	 * 删除订单
	 * 
	 * @param id
	 */
	@Expose
	@Transactional
	public void deleteOrder(String id) {
		JpaUtil.lind(OrderExpense.class).equal("orderId", id).delete();
		JpaUtil.lind(OrderSendReceive.class).equal("orderId", id).delete();
		JpaUtil.lind(Order.class).or().equal("targetId", id).equal("id", id).end().delete();
	}

	@Expose
	@Transactional(readOnly = true)
	public Double intoExpenseVal(Map<String, Object> params) {
		String orderId = (String) params.get("orderId");
		String type = (String) params.get("type");
		String customerId = (String) params.get("customerId");
		String expenseItemId = (String) params.get("expenseItemId");
		String boxType = (String) params.get("boxType");
		Date orderDate = (Date) params.get("orderDate");
		List<OrderSendReceive> orderReceiveList = (List<OrderSendReceive>) params.get("orderReceive");
		if (StringUtils.isNotEmpty(customerId) && StringUtils.isNotEmpty(boxType) && orderDate != null && orderReceiveList != null && orderReceiveList.size() > 0) {
			Calendar c = Calendar.getInstance();
			c.setTime(orderDate);
			c.set(Calendar.HOUR_OF_DAY, 0);
			c.set(Calendar.MINUTE, 0);
			c.set(Calendar.SECOND, 0);
			Date start = c.getTime();
			c.set(Calendar.HOUR_OF_DAY, 23);
			c.set(Calendar.MINUTE, 59);
			c.set(Calendar.SECOND, 59);
			Date end = c.getTime();
			List<OrderExpense> list = JpaUtil.linq(OrderExpense.class).collect(Order.class, "orderId").equal("type", type).equal("expenseItemId", expenseItemId)
					.between("orderData", start, end).exists(Order.class).equal("customerId", customerId).equal("boxType", boxType).addIf("orderId").notEqual("id", orderId).endIf()
					.end().desc("orderDate").list();
			if (list.isEmpty()) {
				return null;
			} else {
				list.get(0).getExpenseVal();
			}
		}
		return null;
	}

	/**
	 * 检查订单是否可以财务完结。只有应收、应付费用都已结清时才能完结。
	 * 
	 * @param orderId
	 */
	private void validateFinaceEnd(String orderId,String orderNo) {
		String hql = "select min(oe.jszt) from " + OrderExpense.class.getName() + " as oe where type<>'2' and oe.orderId=:orderId and oe.expenseVal<>0";
		Map<String, Object> parameterMap = new HashMap<String, Object>();
		parameterMap.put("orderId", orderId);
		String jszt = (String) this.hibernateDao.query(hql, parameterMap, this.hibernateDao.getSession(OrderExpense.class)).get(0);
		if (jszt != null && !"2".equals(jszt)) {
			throw new UnsupportedOperationException("订单【"+orderNo+"】的费用尚未完全结清，不能财务完结！");
		}
	}

	/**
	 * 修改费用前交验是否允许修改改费用
	 * 
	 * @param id
	 */
	public void validateOrderExpenseJszt(String id) {
		Session session = this.hibernateDao.getSession(OrderExpense.class);
		String sql = "SELECT\n" + "	oe.jszt_,\n" + "	ei.name_,\n" + "	oe.expense_val_,\n" + "	o.order_no_\n" + "FROM\n" + "	t_order_expense oe\n"
				+ "INNER JOIN t_order o ON oe.order_id_ = o.id_\n" + "LEFT JOIN t_expense_item ei ON oe.expense_item_id_ = ei.id_\n" + "WHERE\n" + "	oe.id_ =:id";
		SQLQuery query = session.createSQLQuery(sql);
		Object[] array = (Object[]) query.addScalar("jszt_", StringType.INSTANCE).addScalar("name_", StringType.INSTANCE).addScalar("expense_val_", DoubleType.INSTANCE)
				.addScalar("order_no_", StringType.INSTANCE).setString("id", id).uniqueResult();
		String jszt = (String) array[0];
		String name = (String) array[1];
		Double expenseVal = (Double) array[2];
		if (expenseVal != null && expenseVal != 0 && !"0".equals(jszt)) {
			throw new UnsupportedOperationException("订单" + array[3] + "的" + name + "尚未正在核销中，不能修改费用值！");
		}
	}

	private String getStatus(Order order) {
		if (StringUtils.isNotBlank(order.getCarNo()) || StringUtils.isNotBlank(order.getDriverName()) || StringUtils.isNotBlank(order.getDriverTel())) {
			return "1";// 已派车
		} else {
			return "0";// 0：已接单
		}
	}

	private class OrderSmartSavePolicyAdapter extends SmartSavePolicyAdapter {

		@Override
		public void apply(SaveContext context) {
			Object entity = context.getEntity();
			EntityManager entityManager = context.getEntityManager();
			EntityState state = EntityUtils.getState(entity);
			if (EntityState.NEW.equals(state)) {
				beforeInsert(context);
				try {
					entityManager.persist(entity);
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
				afterInsert(context);
			} else if (EntityState.MODIFIED.equals(state) || EntityState.MOVED.equals(state)) {
				beforeUpdate(context);
				try {
					entityManager.merge(entity);
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
				afterUpdate(context);
			} else if (EntityState.DELETED.equals(state)) {
				beforeDelete(context);
				try {
					entityManager.remove(entityManager.merge(entity));
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
				afterDelete(context);
			}
		}

		@Override
		public boolean beforeInsert(SaveContext context) {
			Object parent = context.getParent();
			Object entity = context.getEntity();
			if (entity instanceof Order) {
				// 插入前对Order进行一些处理
				((Order) entity).setStatus(getStatus((Order) entity));
//				if (StringUtils.isNotBlank(((Order) entity).getCarId())) {
//					// 如果车辆不为空，则设置为已派车
//					((Order) entity).setStatus("1");// 已派车
//				} else {
//					((Order) entity).setStatus("0");// 0：已接单
//				}
				if (((Order) entity).getSfst() == 1) {
					// 双拖，生成一个新的拼箱订单
					// 2017-06-12 不再生成新的拼箱单
//					((Order) entity).setTogetherId(generateTogetherOrder((Order) entity).getId());
				} else {
					int quantity = ((Order) entity).getQuantity();
					if (quantity > 1) {
						String baseOrderNo = ((Order) entity).getOrderNo();
						if (StringUtils.isEmpty(baseOrderNo)) {
							baseOrderNo = OrderNoGeneratorPolicy.getOrderNo(((Order) entity).getType());
						}
						((Order) entity).setOrderNo(baseOrderNo + "-001");
						generateOrder((Order) entity, baseOrderNo, quantity);
						((Order) entity).setQuantity(1);
						String cntNo = ((Order) entity).getCntNo();
						if (StringUtils.contains(cntNo, ",")) {
							cntNo = StringUtils.split(cntNo, ",")[0];
						}
						((Order) entity).setCntNo(cntNo);
					}
				}

			}
			if (parent instanceof Order && entity instanceof OrderExpense) {
				// OrderExpense插入前对其进行一些处理
				OrderExpense expense = (OrderExpense) entity;
				expense.setOrderId(((Order) parent).getId());
			}
			if (parent instanceof Order && entity instanceof OrderSendReceive) {
				// OrderSendReceive插入前对其进行一些处理
				OrderSendReceive osr = (OrderSendReceive) entity;
				osr.setOrderId(((Order) parent).getId());
			}
			return true;
		}

		@Override
		public boolean beforeUpdate(SaveContext context) {
			Object parent = context.getParent();
			Object entity = context.getEntity();
			if (entity instanceof Order) {
				int oldFinanceEnd = EntityUtils.getOldInt(entity, "financeEnd");
				int newFinanceEnd = EntityUtils.getInt(entity, "financeEnd");
				if (oldFinanceEnd != newFinanceEnd && newFinanceEnd == 1) {
					// 需要交验是否可以设置财务完结
					validateFinaceEnd(((Order) entity).getId(),((Order) entity).getOrderNo());
				}
//				int oldSfst = EntityUtils.getOldInt(entity, "sfst");
//				int newSfst = ((Order) entity).getSfst();
//				if (oldSfst != newSfst) {
//					// 是否双拖 改变了
//					if (oldSfst == 0) {
//						// 原来非双拖，现在是双拖，生成一个新的拼箱订单
//						// 2017-06-12 不再生成新的拼箱单
////						((Order) entity).setTogetherId(generateTogetherOrder((Order) entity).getId());
//					} else {
//						// 原来双拖，现在非双拖，则解除关系
//						dissolutionTogetherOrder((Order) entity);
//					}
//				}
				((Order) entity).setStatus(getStatus((Order) entity));
//				if (StringUtils.isNotBlank(((Order) entity).getCarId())) {
//					// 如果车辆不为空，则设置为已派车
//					((Order) entity).setStatus("1");// 已派车
//				} else {
//					((Order) entity).setStatus("0");// 0：已接单
//				}
			}
			if (parent instanceof Order && entity instanceof OrderExpense) {
				OrderExpense expense = (OrderExpense) entity;
				validateOrderExpenseJszt(expense.getId());
			}
			return true;
		}
	}

	@DataProvider
	public Map<String, Object> loadBoxtype() {
		Map<String, Object> map = new LinkedHashMap<String, Object>();
		map.put("-1", "20GP/20'普通箱");
		map.put("0", "20RF/20'冷藏箱");
		map.put("1", "20OT/20'开顶箱");
		map.put("2", "20FR/20'框架箱");
		map.put("3", "20TK/20'油罐箱");
		map.put("4", "20RH/冷藏高箱");
		map.put("5", "20HC/2510/20'高箱9.6");
		map.put("6", "20PC/20'平板箱");
		map.put("7", "40GP/40'普通箱");
		map.put("8", "20VE/20'挂衣箱");
		map.put("9", "40VE/40'挂衣箱");
		map.put("10", "20HT/20'超高开顶箱");
		map.put("11", "40HT/40'超高开顶箱");
		map.put("12", "40RF/40'冷藏箱");
		map.put("13", "40OT/40'开顶箱");
		map.put("14", "40FR/40'框架高箱");
		map.put("15", "40FR/40'框架普箱");
		map.put("16", "40HC/40'高箱");
		map.put("17", "40PC/40'平板箱");
		map.put("18", "40HT/40'挂衣高箱");
		map.put("19", "40HH/HALF HEIGHT CNTR");
		map.put("20", "20OS/OPEN SIDE CONTAINER");
		map.put("21", "40RH/冷藏高箱");
		map.put("22", "45GP/45'普通箱");
		map.put("23", "45HC/45'高箱");
		return map;
	}

	/**
	 * 送货单
	 * 
	 * @param params
	 * @return
	 * @throws IOException
	 */
	@FileProvider
	@Transactional
	public DownloadFile getShd(Map<String, Object> params) throws Exception {
		String ids = (String) params.get("ids");
		Object[] idArray = StringUtils.split(ids, ",");
		List<Order> orders = JpaUtil.linq(Order.class).collect(Vessel.class, "vesselId").collect(Port.class, "startPortId", "endPortId").in("id", idArray).list();

		Resource fileRource = new ClassPathResource("cn/portx/view/货代送单.xls");
		Workbook wb = WorkbookFactory.create(fileRource.getInputStream());
		Sheet sheet = wb.getSheetAt(0);
		Row row0 = sheet.createRow(0);
		row0.setHeightInPoints(25);
		Font font = wb.createFont();
		font.setBold(true);
		CellStyle cs = wb.createCellStyle();
		cs.setAlignment(HorizontalAlignment.CENTER);
		cs.setVerticalAlignment(VerticalAlignment.CENTER);
//		cs.setBorderBottom(BorderStyle.THIN);
//		cs.setBorderLeft(BorderStyle.THIN);
//		cs.setBorderRight(BorderStyle.THIN);
//		cs.setBorderTop(BorderStyle.THIN);
		cs.setFont(font);
//		cs.setFillPattern(FillPatternType.SOLID_FOREGROUND);
//		cs.setFillForegroundColor((short) 10);
		for (int i = 0; i < 14; i++) {
			Cell cell = row0.createCell(i);
			cell.setCellStyle(cs);
			if (i == 0) {
				cell.setCellValue(ContextHolder.getLoginOrganization().getName());
			}
		}
		CellRangeAddress rangeCell = new CellRangeAddress(0, 0, 0, 13);
		sheet.addMergedRegion(rangeCell);
		
		
		
		
		System.out.println(sheet.getRow(1).getCell(0).getStringCellValue());

		for (int i = 5; i < orders.size() + 5; i++) {
			Order order = orders.get(i - 5);
			Row row = sheet.createRow(i);

			Cell cell0 = row.createCell(0);
			cell0.setCellValue(i - 4 + "");

			Cell cell1 = row.createCell(1);
			cell1.setCellValue(order.getStartPort() == null ? "" : order.getStartPort().getName());

			Cell cell2 = row.createCell(2);
			cell2.setCellValue(order.getEndPort() == null ? "" : order.getEndPort().getName());

			Cell cell3 = row.createCell(3);
			cell3.setCellValue(order.getVessel() == null ? null : order.getVessel().getName() + "/" + order.getVoyage());

			Cell cell4 = row.createCell(4);
			cell4.setCellValue(order.getBillNo());

			Cell cell5 = row.createCell(5);
			cell5.setCellValue((String) this.loadBoxtype().get(order.getBoxType()));

			Cell cell6 = row.createCell(6);
			if(order.getSfst()==0){
				cell6.setCellValue(order.getCntNo());
			}else{
				if(StringUtils.isNotBlank(order.getCntNo2())){
					cell6.setCellValue(order.getCntNo()+","+order.getCntNo2());
				}
			}
			
			Cell cell7 = row.createCell(7);
			cell7.setCellValue(order.getSealNo());

			Cell cell8 = row.createCell(8);
			cell8.setCellValue(order.getGoodsName());

			Cell cell9 = row.createCell(9);
			cell9.setCellValue(order.getHuozhong() == null ? "" : (order.getHuozhong() + " 吨"));

			OrderSendReceive osr = this.getSendReceiver(order.getId());
			Cell cell10 = row.createCell(10);
			cell10.setCellValue(osr == null ? null : osr.getContact());

			Cell cell11 = row.createCell(11);
			cell11.setCellValue(osr == null ? null : osr.getAddress());

			Cell cell12 = row.createCell(12);
			cell12.setCellValue(osr == null ? null : osr.getTel());

			Cell cell13 = row.createCell(13);
		}
		try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
			wb.write(out);
			wb.close();
			ByteArrayInputStream input = new ByteArrayInputStream(out.toByteArray());
			DownloadFile df = new DownloadFile("report.xls", input);
			return df;
		}

	}

	/**
	 * 签收单
	 * 
	 * @param params
	 * @return
	 * @throws IOException
	 */
	@FileProvider
	@Transactional
	public DownloadFile getQsd(Map<String, Object> params) throws IOException {
		String id = (String) params.get("id");
		Order order = this.loadOrder(id);
		Map<String, String> data = new HashMap<String, String>();
		data.put("${companyName}", ContextHolder.getLoginOrganization().getName());

		data.put("${shipName}", order.getVessel() == null ? null : order.getVessel().getName() + "/" + order.getVoyage());
		data.put("${billNo}", order.getBillNo());
		data.put("${boxType}", (String) this.loadBoxtype().get(order.getBoxType()));
		if(order.getSfst()==0){
			data.put("${cntNo}", order.getCntNo());
		}else{
			if(StringUtils.isNotBlank(order.getCntNo2())){
				data.put("${cntNo}", order.getCntNo()+","+order.getCntNo2());
			}
		}
		data.put("${goodsName}", order.getGoodsName());
		data.put("${huozhong}", order.getHuozhong() == null ? null : (order.getHuozhong() + ""));

		OrderSendReceive osr = this.getSendReceiver(id);
		data.put("${receiver}", osr==null?"":osr.getContact());
		data.put("${tel}", osr==null?"":osr.getTel());
		data.put("${address}", osr==null?"":osr.getAddress());
		data.put("${date}", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));

		Resource fileRource = new ClassPathResource("cn/portx/view/签收单.docx");
		Path path = Files.createTempFile(UUID.randomUUID().toString(), ".docx");
		File file = path.toFile();
		XWPFDocument doc = null;
		try (InputStream in = fileRource.getInputStream()) {
			doc = new XWPFDocument(in);
		}

		//获取整个文本对象
		List<XWPFParagraph> allParagraph = doc.getParagraphs();

		//获取XWPFRun对象输出整个文本内容
		for (XWPFParagraph xwpfParagraph : allParagraph) {
			String text = xwpfParagraph.getText();
			String place = StringUtils.substringBetween(text, "${", "}");
			if (StringUtils.isNotBlank(place)) {
				place = "${" + place + "}";

				List<XWPFRun> runs = xwpfParagraph.getRuns();
				for (int i = 0; i < runs.size(); i++) {
					XWPFRun run = runs.get(i);
					String content = run.getText(run.getTextPosition());
					if (StringUtils.contains(content, place)) {
						//替换模板原来位置
						run.setText(StringUtils.defaultIfBlank(data.get(place), ""), 0);
					}
				}
			}
		}
		List<XWPFTable> tables = doc.getTables();
		for (XWPFTable table : tables) {
			List<XWPFTableRow> rows = table.getRows();
			for (XWPFTableRow row : rows) {
				List<XWPFTableCell> cells = row.getTableCells();
				for (XWPFTableCell cell : cells) {
					//判断单元格是否需要替换
					String text = cell.getText();
					String place = StringUtils.substringBetween(text, "${", "}");
					if ("goodsName".equals(place))
						System.out.println();
					if (StringUtils.isNotBlank(place)) {
						place = "${" + place + "}";
						List<XWPFParagraph> paragraphs = cell.getParagraphs();
						for (XWPFParagraph paragraph : paragraphs) {
							List<XWPFRun> runs = paragraph.getRuns();
							for (int i = 0; i < runs.size(); i++) {
								XWPFRun run = runs.get(i);
								String content = run.getText(run.getTextPosition());
								if (StringUtils.contains(content, place)) {
									//替换模板原来位置
									run.setText(StringUtils.defaultIfBlank(data.get(place), ""), 0);
								}
							}
						}
					}
				}
			}
		}

		try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
			doc.write(out);
			doc.close();
			ByteArrayInputStream input = new ByteArrayInputStream(out.toByteArray());
			DownloadFile df = new DownloadFile("report.docx", input);
			return df;
		}
	}

	private OrderSendReceive getSendReceiver(String orderId) {
		List<OrderSendReceive> list = JpaUtil.linq(OrderSendReceive.class).equal("orderId", orderId).equal("type", "0").list();
		return list.isEmpty() ? null : list.get(0);
	}
}
